<?php

/**
 * MyHammer IndexedMemcache
 *
 * LICENSE
 *
 * This source file is subject to the GNU General Public License Version 3
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://www.myhammer.de/opensource/license/gpl.txt
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to opensource@myhammer.de so we can send you a copy immediately.
 *
 * @category   MyHammer
 * @package    IndexedMemcache
 * @subpackage utils
 * @license    http://www.myhammer.de/opensource/license/gpl.txt GNU General Public License Version 3
 * @version    1.0
 * @author     Steven Berg <berg@myhammer.de>
 */

class cProfiler {
    const IDENTIFIER = 'identifier';
    const START_TIME = 'startTime';
    const END_TIME = 'endTime';
    const DESCRIPTION = 'description';
    const BACKTRACE_START = 'backtrace_start';
    const BACKTRACE_END = 'backtrace_end';
    const MEMORY_START = 'memory_start';
    const MEMORY_END = 'memory_end';

    private $aPoints = array();
    private $aTempPoints = array();

    private static $oProfiler = NULL;

    /**
     * constructor
     */
    private function __construct() {

    }

    /**
     * destructor
     */
    public function __destruct() {
        if (cConfigMemCache::SHOW_PROFILER) {
            self::endPoint('SCRIPT');
            $this->output();
        }
    }

    /**
     * get cProfilerObject
     *
     * @return cProfiler
     */
    public static function getInstance() {

        if (self::$oProfiler === NULL) {
            self::$oProfiler = new self;
            self::startPoint('SCRIPT');
        }
        return self::$oProfiler;
    }

    /**
     * set Profiler StartPoint
     *
     * @param string $sIdentifier
     * @param string $sDescription
     */
    public static function startPoint($sIdentifier, $sDescription = NULL) {
        if (cConfigMemCache::SHOW_PROFILER) {
            $aPoint = array();
            $aPoint[self::IDENTIFIER] = $sIdentifier;
            $aPoint[self::DESCRIPTION] = $sDescription;
            $aPoint[self::START_TIME] = microtime(TRUE);
            $aPoint[self::BACKTRACE_START] = self::getBackTraceInfo();
            $aPoint[self::MEMORY_START] = self::getMemoryUsage();
            self::getInstance()->aTempPoints[$sIdentifier] = $aPoint;
        }
    }

    /**
     * set Profiler EndPoint
     *
     * @param string $sIdentifier
     */
    public static function endPoint($sIdentifier) {
        if (cConfigMemCache::SHOW_PROFILER) {
            $aTempPoints = self::getInstance()->aTempPoints;
            if (array_key_exists($sIdentifier, $aTempPoints)) {
                $aPoint = $aTempPoints[$sIdentifier];
                $aPoint[self::END_TIME] = microtime(TRUE);
                $aPoint[self::BACKTRACE_END] = self::getBackTraceInfo();
                $aPoint[self::MEMORY_END] = self::getMemoryUsage();
                self::getInstance()->aPoints[] = $aPoint;
            }
        }
    }

    /**
     * display profiler steps
     */
    public function output() {
        $iCurrentStep = 0;

        echo "<pre style='margin: 0px 0px 10px 0px; display: block; background: white; color: black; font-family: Verdana; border: 1px solid #cccccc; padding: 5px; font-size: 10px; line-height: 13px;'>";
        echo '<b style="color: black; font-size: 150%;"><u>Profiler</u></b><br><br>';

        foreach ($this->aPoints as $iStep => $aPoint) {
            $iCurrentStep++;

            echo "<pre style='margin: 0px 0px 10px 0px; display: block; background: white; color: black; font-family: Verdana; border: 1px solid #cccccc; padding: 5px; font-size: 10px; line-height: 13px;'>";

            echo '<b><u>Step: ' . $iCurrentStep;

            if (!is_null($aPoint[self::DESCRIPTION])) {
                echo ' - Description: '.  $aPoint[self::DESCRIPTION];
            }

            echo ' - Identifier: ' . $aPoint[self::IDENTIFIER] . '</u></b><br><br>';

            echo '<span style="color: black;">StartFile: ' . $aPoint[self::BACKTRACE_START] . '</span><br>';
            echo '<span style="color: black;">Memory: ' . $aPoint[self::MEMORY_START] . '</span><br>';


            echo '<sapn style="color: black;">EndFile:   ' . $aPoint[self::BACKTRACE_END] . '</span><br>';
            echo '<span style="color: black;">Memory: ' . $aPoint[self::MEMORY_END] . '</span><br>';

            echo '<b style="color: black;">Duration:   ' . sprintf('%010f s', $aPoint[self::END_TIME] - $aPoint[self::START_TIME]) . '</b><br>';

            echo "</pre>";
        }

        echo '</pre>';
    }

    /**
     * get Line and File from BackTrace
     *
     * @return string
     */
    public static function getBackTraceInfo() {
        $aBackTrace = debug_backtrace();
        $iLine = $aBackTrace[1]['line'];
        $sFile = $aBackTrace[1]['file'];
        return 'Line: '. $iLine . '  File: ' . $sFile;
    }

    /**
     * get Memory Usage
     *
     * @return string
     */
    public static function getMemoryUsage() {
        $mem_usage = memory_get_usage(true);

        if ($mem_usage < 1024) {
            return $mem_usage." bytes";
        } elseif ($mem_usage < 1048576) {
            return round($mem_usage/1024,2)." kilobytes";
        } else {
            return round($mem_usage/1048576,2)." megabytes";
        }
    }
}